home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-02-18 | 9.5 KB | 266 lines | [TEXT/MPS ] |
- {------------------------------------------------------------------------------
- #
- # Macintosh Developer Technical Support
- #
- # EditText Sample Control Panel Device
- #
- # EditCdev
- #
- # EditCdev.p - Pascal Source
- #
- # Copyright © 1988 Apple Computer, Inc.
- # All rights reserved.
- #
- # Versions: 1.00 8/88
- # 1.10 6/92
- #
- # Components: EditCdev.p August 1, 1988
- # EditCdev.c August 1, 1988
- # EditCdev.r August 1, 1988
- # PEditCdev.make August 1, 1988
- # CEditCdev.make August 1, 1988
- # TCEditCdev.π June 12, 1992
- # TCEditCdev.π.rsrc June 12, 1992
- #
- # EditCdev is a sample Control Panel device (cdev) that
- # demonstrates the usage of the edit-related messages.
- # EditCdev demonstrates how to implement an editText item
- # in a Control Panel Device. It utilizes the new undo, cut, copy,
- # paste, and delete messages that are sent to cdevs in
- # response to user menu selections.
- #
- # It is comprised of two editText items that can be edited
- # and moved between via the mouse or tab key.
- #
- ------------------------------------------------------------------------------}
-
- UNIT EditTextCDEV;
-
- INTERFACE
-
- USES
-
- Types, Memory, Dialogs, QuickDraw, Events, Controls, Windows, TextEdit,
- Fonts, Lists, Menus, Resources, Scrap, ToolUtils, TextUtils,
- OSUtils, Files, Devices, DeskBus, DiskInit, Disks, Errors, Retrace, SegLoad, Serial,
- ShutDown, Slots, Sound, Start, Timer, Packages;
-
-
- CONST
-
- textItm = 1; {first editTExt item in cdev}
- countItm = 4; {first staticText item for displaying character count}
-
- maxLength = 50; {maximum # of characters in each textEdit field < 32K}
-
- delete = $08; {character codes for various keys}
- tab = $09;
- leftArrow = $1c;
- rightArrow = $1d;
- upArrow = $1e;
- downArrow = $1f;
-
-
- TYPE {Storage for CDEV - All permanent CDEV storage must be referred to}
- {by a single handle, so put all permanent variables in a CDEVRec. }
- CDEVRec = RECORD
- needUpdate : BOOLEAN;
- END;
- CDEVPtr = ^CDEVRec;
- CDEVHnd = ^CDEVPtr;
- {$main}
- FUNCTION TextCDEV (message, item, numItems, CPanelID: INTEGER;
- VAR theEvent: EventRecord;
- cdevStorage: CDEVHnd;
- CPDialog: DialogPtr) : CDEVHnd;
-
- IMPLEMENTATION
-
- PROCEDURE DoEditCommand (message: INTEGER; CPDialog: DialogPtr); FORWARD;
-
- PROCEDURE UpdateCharCount(CPDialog: DialogPtr); FORWARD;
-
- FUNCTION TextCDEV (message, item, numItems, CPanelID: INTEGER;
- VAR theEvent: EventRecord;
- cdevStorage: CDEVHnd;
- CPDialog: DialogPtr) : CDEVHnd;
-
- {* This is the main dispatcher. It must be the first code in the cdev.
- * EditCdev's dispatcher responds only to the following messages from
- * the Control Panel:
- *
- * macDev - To indicate what machines it is available on.
- * nulDev - To check if the character count items need to be updated.
- * initDev - To set up some temporary storage and get the caret started.
- * keyEvtDev - To check for an edit command and do the appropriate action.
- * cutDev - To cut the current selection.
- * copyDev - To copy the current selection.
- * pasteDev - To paste the contents of the clipboard.
- * clearDev - To delete the current selection.
- *
- * The Dialog Manager's services are used to handle entry of text, selection
- * of text, editing of text, and moving between the editText items via the
- * tab key. Since the Dialog Manager handles the selection of text, we do not
- * have to be concerned with hitDev messages for the editText items. The only
- * things we have to take care of are calling the Dialog Manager editing
- * routines in response to an edit command, and getting the caret to show up
- * at the beginning. In response to an edit command that was the result of
- * a command-key equivalent, we must also eliminate the event so that it does
- * not get processed as a keyDown by the Dialog Manager. Otherwise, an 'x'
- * would show up in the editText item when the user did a command-x to cut
- * the text.
- * Also, we must be aware that the dialog manager does not keep track
- * of the length of the characters typed or pasted into the textEdit items.
- * Since the maximum number of characters that may be contained in a single
- * textEdit item is 32K, we must make sure that the user does not enter more
- * than some maximum number of characters.}
-
- VAR
- tempChar : CHAR;
- myTEHandle : TEHandle; {handle to the current textEdit record}
- selLength : INTEGER; {length of current selection}
- BEGIN
- IF message = macDev THEN TextCDEV := CDEVHnd(1) {we work on every machine}
- ELSE IF cdevStorage <> NIL THEN BEGIN
- CASE message OF
- initDev: {initialize cdev}
- BEGIN
- cdevStorage := CDEVHnd(NewHandle(SIZEOF(CDEVRec))); {create private storage}
- SelectDialogItemText(CPDialog, numItems + textItm, 0, 999); {make caret show up}
- END;
- nulDev:
- BEGIN
- IF cdevStorage^^.needUpdate THEN {character count need updating?}
- BEGIN
- UpdateCharCount(CPDialog);
- cdevStorage^^.needUpdate := false;
- END;
- END;
- hitDev:;
- closeDev:;
- updateDev:;
- activDev:;
- deActivDev:;
- keyEvtDev: {respond to key down}
- BEGIN
- {first, get the character}
- tempChar := CHR(BAnd(theEvent.message, charCodeMask));
- {then see if the command key was down}
- IF BAnd(theEvent.modifiers, cmdKey) <> 0 THEN BEGIN
- message := nulDev; {start off with no message}
- theEvent.what := nullEvent; {wipe out event}
- CASE tempChar OF {set appropriate message}
- 'X','x':
- message := cutDev;
- 'C','c':
- message := copyDev;
- 'V','v':
- message := pasteDev;
- END;
- DoEditCommand(message, CPDialog); {let edit command handler take it}
- END
- ELSE BEGIN {not a command key}
- { We need to update the character count, but only after textEdit has }
- { a chance to deal with it. Set a flag so that during the next nullEvent }
- { we will process the character count update. If we call UpdateCharCount }
- { now, we will display the incorrect count. }
- { Also, we must make sure that we are not exceeding our character limit }
- { with this character. (unless it is a tab or backspace, that's OK) }
-
- cdevStorage^^.needUpdate := true; {update count during next nulDev}
-
- myTEHandle := DialogPeek(CPDialog)^.textH;
- selLength := (myTEHandle^^.selEnd-myTEHandle^^.selStart);
-
- IF (myTEHandle^^.teLength>=maxLength+selLength) AND
- (ORD(tempChar)<>delete) AND (ORD(tempChar)<>tab) AND
- (ORD(tempChar)<>rightArrow) AND (ORD(tempChar)<>leftArrow) AND
- (ORD(tempChar)<>upArrow) AND (ORD(tempChar)<>downArrow) THEN BEGIN
- theEvent.what := nullEvent; {trash character (so textEdit never sees it)}
- SysBeep(1);
- END;
- END;
- END;
- macDev:;
- undoDev:;
- cutDev, copyDev, pasteDev, clearDev:
- DoEditCommand(message, CPDialog); {respond to edit command}
- END; {CASE message}
- TextCDEV := cdevStorage; {if cdevStorage = NIL then ControlPanel will put up memory error}
- END; {cdevStorage <> NIL}
- END; {TextCDEV}
-
- PROCEDURE DoEditCommand (message: INTEGER; CPDialog: DialogPtr);
-
- { Call the appropriate Dialog Manager routine to handle an edit command for }
- { an editText item. It will do *ALMOST* all the work regarding the TEScrap. }
-
- VAR
- myTEHandle : TEHandle; {Handle to current textEdit record}
- scrapLength : LONGINT; {length of textEdit scrap}
- freeSpace : LONGINT; {amount of space before character limit}
- selLength : INTEGER; {length of current selection}
- BEGIN
- myTEHandle := DialogPeek(CPDialog)^.textH;
-
- CASE message OF
- cutDev:
- DialogCut(CPDialog);
- copyDev:
- DialogCopy(CPDialog);
- pasteDev:
- { Since the maximum number of characters that a textEdit structure can }
- { handle is 32K, and the dialog manager doesn't check for overflow when }
- { pasting, we must check for ourselves and only paste as many characters }
- { as we have room for. }
- BEGIN
- scrapLength := TEGetScrapLength;
- selLength := (myTEHandle^^.selEnd)-(myTEHandle^^.selStart);
- freeSpace := LONGINT(maxLength-(myTEHandle^^.teLength)+selLength);
- IF freeSpace>=scrapLength THEN {enough room for paste?}
- DialogPaste(CPDialog)
- ELSE BEGIN {not enough room for paste}
- SysBeep(1);
- IF freeSpace>0 THEN BEGIN {any room for paste?}
- TESetScrapLength(freeSpace); {only paste as many characters as free}
- DialogPaste(CPDialog);
- TESetScrapLength(scrapLength); {restore textEdit scrap length}
- END;
- END;
- END;
- clearDev:
- DialogDelete(CPDialog);
- END;
- UpdateCharCount(CPDialog);
- END; {DoEditCommand}
-
-
- { Examine the appropriate structures to determine the number of characters in the }
- { acvive TERecord and display in the corresponding static text item. }
- { Note that since we can only have one code segment in a CDEV, we must use the $R- }
- { directive to tell the compiler not to do string range checking. When the }
- { compiler does checking, it attempts to load the checking routines from PasLib.o, }
- { and into another segment. An alternate solution is to force the linker to put }
- { the string length checking routines into the main segment with the -sn option. }
-
- {$R-} {Turns off string range checking}
-
- PROCEDURE UpdateCharCount(CPDialog: DialogPtr);
- VAR
- myTEHandle : TEHandle;
- itemType : INTEGER;
- itemHandle : Handle;
- itemRect : Rect;
- text : Str255;
- editItem : INTEGER;
- BEGIN
- myTEHandle := DialogPeek(CPDialog)^.textH; {get handle to TERecord}
- HLock(Handle(myTEHandle));
- NumToString(LONGINT(myTEHandle^^.teLength), text); {get length of text}
- HUnlock(Handle(myTEHandle));
- editItem:=countItm+DialogPeek(CPDialog)^.editField; {calculate which item to change}
- GetDialogItem(CPDialog, editItem, itemType, itemHandle, itemRect);
- SetDialogItemText(itemHandle, text); {change text item contents}
- END;
- END. {EditTextCDEV}
-